diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/font-syn.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/font-syn.lua | 592 |
1 files changed, 334 insertions, 258 deletions
diff --git a/Master/texmf-dist/tex/context/base/font-syn.lua b/Master/texmf-dist/tex/context/base/font-syn.lua index c4f0e948b87..81e27afd603 100644 --- a/Master/texmf-dist/tex/context/base/font-syn.lua +++ b/Master/texmf-dist/tex/context/base/font-syn.lua @@ -8,18 +8,30 @@ if not modules then modules = { } end modules ['font-syn'] = { -- todo: subs in lookups requests -local utf = unicode.utf8 -local next, tonumber = next, tonumber -local gsub, lower, match, find, lower, upper = string.gsub, string.lower, string.match, string.find, string.lower, string.upper +local next, tonumber, type, tostring = next, tonumber, type, tostring +local sub, gsub, lower, match, find, lower, upper = string.sub, string.gsub, string.lower, string.match, string.find, string.lower, string.upper local find, gmatch = string.find, string.gmatch local concat, sort, format = table.concat, table.sort, string.format local serialize = table.serialize local lpegmatch = lpeg.match -local utfgsub, utflower = utf.gsub, utf.lower local unpack = unpack or table.unpack +local formatters = string.formatters -local allocate = utilities.storage.allocate -local sparse = utilities.storage.sparse +local allocate = utilities.storage.allocate +local sparse = utilities.storage.sparse + +local removesuffix = file.removesuffix +local splitbase = file.splitbase +local splitname = file.splitname +local basename = file.basename +local nameonly = file.nameonly +local pathpart = file.pathpart +local filejoin = file.join +local is_qualified_path = file.is_qualified_path + +local findfile = resolvers.findfile +local cleanpath = resolvers.cleanpath +local resolveresolved = resolvers.resolve 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) @@ -34,13 +46,13 @@ using a table that has keys filtered from the font related files.</p> fonts = fonts or { } -- also used elsewhere -local names = { } +local names = font.names or allocate { } fonts.names = names -names.filters = names.filters or { } -local filters = names.filters +local filters = names.filters or { } +names.filters = filters -names.data = names.data or { } +names.data = names.data or allocate { } names.version = 1.110 names.basename = "names" @@ -121,6 +133,50 @@ local variants = Cs( -- fax casual local normalized_variants = sparse() +names.knownweights = { + "black", + "bold", + "demi", + "demibold", + "extrabold", + "heavy", + "light", + "medium", + "mediumbold", + "normal", + "regular", + "semi", + "semibold", + "ultra", + "ultrabold", + "ultralight", +} + +names.knownstyles = { + "italic", + "normal", + "oblique", + "regular", + "reverseitalic", + "reverseoblique", + "roman", + "slanted", +} + +names.knownwidths = { + "book", + "condensed", + "expanded", + "normal", + "thin", +} + +names.knownvariants = { + "normal", + "oldstyle", + "smallcaps", +} + local any = P(1) local analyzed_table @@ -144,13 +200,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 - 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 '') + report_names("requested name %a split in name %a, weight %a, style %a, width %a and variant %a", + askedname,name,weight,style,width,variant) 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 - report_names("request '%s' normalized to '%s-%s-%s-%s-%s'", + report_names("request %a normalized to '%s-%s-%s-%s-%s'", askedname,name,weight,style,width,variant) end end @@ -175,7 +231,7 @@ filters.ttf = fontloader.info filters.ttc = fontloader.info filters.dfont = fontloader.info -function fontloader.fullinfo(...) +function fontloader.fullinfo(...) -- check with taco what we get / could get local ff = fontloader.open(...) if ff then local d = ff and fontloader.to_table(ff) @@ -192,9 +248,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.findfile(file.removesuffix(name)..".pfb","pfb") or "" + local pfbname = findfile(removesuffix(name)..".pfb","pfb") or "" if pfbname == "" then - pfbname = resolvers.findfile(file.removesuffix(file.basename(name))..".pfb","pfb") or "" + pfbname = findfile(nameonly(name)..".pfb","pfb") or "" end if pfbname ~= "" then local f = io.open(name) @@ -228,7 +284,7 @@ for combination with the weight of a font.</p> filters.list = { "otf", "ttf", "ttc", "dfont", "afm", ---~ "ttc", "otf", "ttf", "dfont", "afm", + -- "ttc", "otf", "ttf", "dfont", "afm", } names.fontconfigfile = "fonts.conf" -- a bit weird format, bonus feature @@ -240,11 +296,11 @@ filters.names = { } function names.getpaths(trace) local hash, result, r = { }, { }, 0 local function collect(t,where) - for i=1, #t do - local v = resolvers.cleanpath(t[i]) + for i=1,#t do + local v = cleanpath(t[i]) v = gsub(v,"/+$","") -- not needed any more local key = lower(v) - report_names("adding path from %s: %s",where,v) + report_names("%a specifies path %a",where,v) if not hash[key] then r = r + 1 result[r] = v @@ -263,34 +319,34 @@ function names.getpaths(trace) end if confname ~= "" then -- first look in the tex tree - local name = resolvers.findfile(confname,"fontconfig files") or "" + local name = findfile(confname,"fontconfig files") or "" if name == "" then -- after all, fontconfig is a unix thing - name = file.join("/etc",confname) + name = filejoin("/etc",confname) if not lfs.isfile(name) then name = "" -- force quit end end if name ~= "" and lfs.isfile(name) then if trace_names then - report_names("loading fontconfig file: %s",name) + report_names("%s fontconfig file %a","loading",name) end local xmldata = xml.load(name) -- begin of untested mess xml.include(xmldata,"include","",true,function(incname) - if not file.is_qualified_path(incname) then - local path = file.dirname(name) -- main name + if not is_qualified_path(incname) then + local path = pathpart(name) -- main name if path ~= "" then - incname = file.join(path,incname) + incname = filejoin(path,incname) end end if lfs.isfile(incname) then if trace_names then - report_names("merging included fontconfig file: %s",incname) + report_names("%s fontconfig file %a","merging included",incname) end return io.loaddata(incname) elseif trace_names then - report_names("ignoring included fontconfig file: %s",incname) + report_names("%s fontconfig file: %a","ignoring included",incname) end end) -- end of untested mess @@ -310,12 +366,10 @@ end local function cleanname(name) return (gsub(lower(name),"[^%a%d]","")) - -- once we can load files with utf names, we can play with the following: - -- return (utfgsub(utfgsub(lower(str),"[^%a%A%d]",""),"%s","")) end local function cleanfilename(fullname,defaultsuffix) - local path, name, suffix = file.splitname(fullname) + local path, name, suffix = splitname(fullname) name = gsub(lower(name),"[^%a%d]","") if suffix and suffix ~= "" then return name .. ".".. suffix @@ -345,33 +399,32 @@ local function walk_tree(pathlist,suffix,identify) if pathlist then for i=1,#pathlist do local path = pathlist[i] - path = resolvers.cleanpath(path .. "/") + path = cleanpath(path .. "/") path = gsub(path,"/+","/") local pattern = path .. "**." .. suffix -- ** forces recurse - report_names( "globbing path %s",pattern) + report_names("globbing path %a",pattern) local t = dir.glob(pattern) sort(t,sorter) for j=1,#t do local completename = t[j] - identify(completename,file.basename(completename),suffix,completename) + identify(completename,basename(completename),suffix,completename) end end end end -local function check_name(data,result,filename,suffix,subfont) +local function check_name(data,result,filename,modification,suffix,subfont) -- shortcuts local specifications = data.specifications - local families = data.families -- prepare local names = check_names(result) -- fetch - local familyname = (names and names.preffamilyname) or result.familyname - local fullname = (names and names.fullname) or result.fullname + local familyname = names and names.preffamilyname or result.familyname + local fullname = names and names.fullname or result.fullname local fontname = result.fontname - local subfamily = (names and names.subfamily) - local modifiers = (names and names.prefmodifiers) - local weight = (names and names.weight) or result.weight + local subfamily = names and names.subfamily + local modifiers = names and names.prefmodifiers + local weight = names and names.weight or result.weight local italicangle = tonumber(result.italicangle) local subfont = subfont or nil local rawname = fullname or fontname or familyname @@ -382,7 +435,7 @@ local function check_name(data,result,filename,suffix,subfont) subfamily = subfamily and cleanname(subfamily) modifiers = modifiers and cleanname(modifiers) weight = weight and cleanname(weight) - italicangle = (italicangle == 0) and nil + italicangle = italicangle == 0 and nil -- analyze local a_name, a_weight, a_style, a_width, a_variant = analyzespec(fullname or fontname or familyname) -- check @@ -404,34 +457,38 @@ local function check_name(data,result,filename,suffix,subfont) if not familyname then familyname = a_name end - fontname = fontname or fullname or familyname or file.basename(filename) + fontname = fontname or fullname or familyname or basename(filename) fullname = fullname or fontname familyname = familyname or fontname specifications[#specifications + 1] = { - filename = filename, -- unresolved - format = lower(suffix), - subfont = subfont, - rawname = rawname, - familyname = familyname, - fullname = fullname, - fontname = fontname, - subfamily = subfamily, - modifiers = modifiers, - weight = weight, - style = style, - width = width, - variant = variant, - minsize = result.design_range_bottom or 0, - maxsize = result.design_range_top or 0, - designsize = result.design_size or 0, + filename = filename, -- unresolved + format = lower(suffix), + subfont = subfont, + rawname = rawname, + familyname = familyname, + fullname = fullname, + fontname = fontname, + subfamily = subfamily, + modifiers = modifiers, + weight = weight, + style = style, + width = width, + variant = variant, + minsize = result.design_range_bottom or 0, + maxsize = result.design_range_top or 0, + designsize = result.design_size or 0, + modification = modification or 0, } end local function cleanupkeywords() - local data = names.data + local data = names.data local specifications = names.data.specifications if specifications then - local weights, styles, widths, variants = { }, { }, { }, { } + local weights = { } + local styles = { } + local widths = { } + local variants = { } for i=1,#specifications do local s = specifications[i] -- fix (sofar styles are taken from the name, and widths from the specification) @@ -463,29 +520,40 @@ local function cleanupkeywords() end local function collectstatistics() - local data = names.data + local data = names.data local specifications = data.specifications if specifications then - local weights, styles, widths, variants = { }, { }, { }, { } + local weights = { } + local styles = { } + local widths = { } + local variants = { } for i=1,#specifications do - local s = specifications[i] - local weight, style, width, variant = s.weight, s.style, s.width, s.variant + local s = specifications[i] + local weight = s.weight + local style = s.style + local width = s.width + local variant = s.variant if weight then weights [weight ] = (weights [weight ] or 0) + 1 end if style then styles [style ] = (styles [style ] or 0) + 1 end if width then widths [width ] = (widths [width ] or 0) + 1 end if variant then variants[variant] = (variants[variant] or 0) + 1 end end - local stats = data.statistics - stats.weights, stats.styles, stats.widths, stats.variants, stats.fonts = weights, styles, widths, variants, #specifications + local stats = data.statistics + stats.weights = weights + stats.styles = styles + stats.widths = widths + stats.variants = variants + stats.fonts = #specifications end end local function collecthashes() - local data = names.data + local data = names.data local mappings = data.mappings local fallbacks = data.fallbacks local specifications = data.specifications - local nofmappings, noffallbacks = 0, 0 + local nofmappings = 0 + local noffallbacks = 0 if specifications then -- maybe multiple passes for index=1,#specifications do @@ -498,22 +566,20 @@ local function collecthashes() if fontname and not mf[fontname] then mf[fontname], nofmappings = index, nofmappings + 1 end - if familyname and weight then + if familyname and weight and weight ~= sub(familyname,#familyname-#weight+1,#familyname) then local madename = familyname .. weight if not mf[madename] and not ff[madename] then ff[madename], noffallbacks = index, noffallbacks + 1 end end - if familyname and subfamily then + if familyname and subfamily and subfamily ~= sub(familyname,#familyname-#subfamily+1,#familyname) then local extraname = familyname .. subfamily if not mf[extraname] and not ff[extraname] then ff[extraname], noffallbacks = index, noffallbacks + 1 end end - if familyname then - if not mf[familyname] and not ff[familyname] then - ff[familyname], noffallbacks = index, noffallbacks + 1 - end + if familyname and not mf[familyname] and not ff[familyname] then + ff[familyname], noffallbacks = index, noffallbacks + 1 end end end @@ -521,12 +587,12 @@ local function collecthashes() end local function collectfamilies() - local data = names.data + local data = names.data local specifications = data.specifications - local families = data.families + local families = data.families for index=1,#specifications do local familyname = specifications[index].familyname - local family = families[familyname] + local family = families[familyname] if not family then families[familyname] = { index } else @@ -536,14 +602,15 @@ local function collectfamilies() end local function checkduplicate(where) -- fails on "Romantik" but that's a border case anyway - local data = names.data - local mapping = data[where] - local specifications, loaded = data.specifications, { } + local data = names.data + local mapping = data[where] + local specifications = data.specifications + local loaded = { } if specifications and mapping then for _, m in next, mapping do for k, v in next, m do local s = specifications[v] - local hash = format("%s-%s-%s-%s-%s",s.familyname,s.weight or "*",s.style or "*",s.width or "*",s.variant or "*") + local hash = formatters["%s-%s-%s-%s-%s"](s.familyname,s.weight or "*",s.style or "*",s.width or "*",s.variant or "*") local h = loaded[hash] if h then local ok = true @@ -569,12 +636,12 @@ local function checkduplicate(where) -- fails on "Romantik" but that's a border local nv = #v if nv > 1 then if trace_warnings then - report_names( "double lookup: %s => %s",k,concat(v," | ")) + report_names("lookup %a clashes with %a",k,v) end n = n + nv end end - report_names( "%s double lookups in %s",n,where) + report_names("%a double lookups in %a",n,where) end local function checkduplicates() @@ -587,13 +654,19 @@ local sorter = function(a,b) end local function sorthashes() - local data, list = names.data, filters.list - local mappings, fallbacks, sorted_mappings, sorted_fallbacks = data.mappings, data.fallbacks, { }, { } - data.sorted_mappings, data.sorted_fallbacks = sorted_mappings, sorted_fallbacks + local data = names.data + local list = filters.list + local mappings = data.mappings + local fallbacks = data.fallbacks + local sorted_mappings = { } + local sorted_fallbacks = { } + data.sorted_mappings = sorted_mappings + data.sorted_fallbacks = sorted_fallbacks for i=1,#list do local l = list[i] - sorted_mappings[l], sorted_fallbacks[l] = table.keys(mappings[l]), table.keys(fallbacks[l]) - sort(sorted_mappings[l],sorter) + sorted_mappings [l] = table.keys(mappings[l]) + sorted_fallbacks[l] = table.keys(fallbacks[l]) + sort(sorted_mappings [l],sorter) sort(sorted_fallbacks[l],sorter) end data.sorted_families = table.keys(data.families) @@ -601,7 +674,7 @@ local function sorthashes() end local function unpackreferences() - local data = names.data + local data = names.data local specifications = data.specifications if specifications then for k, v in next, data.families do @@ -628,40 +701,52 @@ local function unpackreferences() end end -local function analyzefiles() - local data = names.data - 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 analyzefiles(olddata) + if not trace_warnings then + report_names("warnings are disabled (tracker 'fonts.warnings')") + end + local data = names.data + local done = { } + local totalnofread = 0 + local totalnofskipped = 0 + local totalnofduplicates = 0 + local nofread = 0 + local nofskipped = 0 + local nofduplicates = 0 + local skip_paths = filters.paths + local skip_names = filters.names + local specifications = data.specifications + local oldindices = olddata and olddata.indices or { } + local oldspecifications = olddata and olddata.specifications or { } + local oldrejected = olddata and olddata.rejected or { } local function identify(completename,name,suffix,storedname) - local basename = file.basename(completename) - local basepath = file.dirname(completename) + local pathpart, basepart = splitbase(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) + report_names("%s font %a already done",suffix,completename) 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) + report_names("%s font %a 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 + elseif not is_qualified_path(completename) and findfile(completename,suffix) == "" then + -- not locatable by backend anyway if trace_names then - report_names("%s font %s cannot be found by backend",suffix,completename) + report_names("%s font %a cannot be found by backend",suffix,completename) end nofskipped = nofskipped + 1 else if #skip_paths > 0 then for i=1,#skip_paths do - if find(basepath,skip_paths[i]) then + if find(pathpart,skip_paths[i]) then if trace_names then - report_names("rejecting path of %s font %s",suffix,completename) + report_names("rejecting path of %s font %a",suffix,completename) end nofskipped = nofskipped + 1 return @@ -670,10 +755,10 @@ local function analyzefiles() end if #skip_names > 0 then for i=1,#skip_paths do - if find(basename,skip_names[i]) then + if find(basepart,skip_names[i]) then done[name] = true if trace_names then - report_names("rejecting name of %s font %s",suffix,completename) + report_names("rejecting name of %s font %a",suffix,completename) end nofskipped = nofskipped + 1 return @@ -681,29 +766,50 @@ local function analyzefiles() end end if trace_names then - report_names("identifying %s font %s",suffix,completename) + report_names("identifying %s font %a",suffix,completename) end - local result, message = filters[lower(suffix)](completename) - if result then - if result[1] then - for r=1,#result do - local ok = check_name(data,result[r],storedname,suffix,r-1) -- subfonts start at zero + local result = nil + local modification = lfs.attributes(completename,"modification") + if olddata and modification and modification > 0 then + local oldindex = oldindices[storedname] -- index into specifications + if oldindex then + local oldspecification = oldspecifications[oldindex] + if oldspecification and oldspecification.filename == storedname then -- double check for out of sync + local oldmodification = oldspecification.modification + if oldmodification == modification then + result = oldspecification + specifications[#specifications + 1] = result + else + end + else + end + elseif oldrejected[storedname] == modification then + result = false + end + end + if result == nil then + local result, message = filters[lower(suffix)](completename) + if result then + if result[1] then + for r=1,#result do + local ok = check_name(data,result[r],storedname,modification,suffix,r-1) -- subfonts start at zero + -- if not ok then + -- nofskipped = nofskipped + 1 + -- end + end + else + local ok = check_name(data,result,storedname,modification,suffix) -- 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 - report_names("warning when identifying %s font %s: %s",suffix,completename,message) + if trace_warnings and message and message ~= "" then + report_names("warning when identifying %s font %a, %s",suffix,completename,message) + end + elseif trace_warnings then + nofskipped = nofskipped + 1 + report_names("error when identifying %s font %a, %s",suffix,completename,message or "unknown") end - elseif trace_warnings then - nofskipped = nofskipped + 1 - report_names("error when identifying %s font %s: %s",suffix,completename,message or "unknown") end done[name] = true end @@ -716,73 +822,85 @@ local function analyzefiles() local t = os.gettimeofday() -- use elapser nofread, nofskipped, nofduplicates = 0, 0, 0 suffix = lower(suffix) - report_names( "identifying %s font files with suffix %s",what,suffix) + report_names("identifying %s font files with suffix %a",what,suffix) method(suffix) suffix = upper(suffix) - report_names( "identifying %s font files with suffix %s",what,suffix) + report_names("identifying %s font files with suffix %a",what,suffix) method(suffix) totalnofread, totalnofskipped, totalnofduplicates = totalnofread + nofread, totalnofskipped + nofskipped, totalnofduplicates + nofduplicates local elapsed = os.gettimeofday() - t - 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) + 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 - report_names( "warnings are disabled (tracker 'fonts.warnings')") - end - traverse("tree", function(suffix) -- TEXTREE only + -- problem .. this will not take care of duplicates + local function withtree(suffix) resolvers.dowithfilesintree(".*%." .. suffix .. "$", function(method,root,path,name) if method == "file" or method == "tree" then local completename = root .."/" .. path .. "/" .. name - completename = resolvers.resolve(completename) -- no shortcut + completename = resolveresolved(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) + blobpath = resolveresolved(blobpath) -- no shortcut + report_names("scanning path %a 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) + blobpath = resolveresolved(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 + end + local function withlsr(suffix) -- all trees -- 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.splitpath(resolvers.showpath("ls-R") or "") - walk_tree(pathlist,suffix,identify) - end) + -- using the vars is too clumsy so we just stick to a full scan instead + local pathlist = resolvers.splitpath(resolvers.showpath("ls-R") or "") + walk_tree(pathlist,suffix,identify) + end + local function withsystem(suffix) -- OSFONTDIR cum suis + walk_tree(names.getpaths(trace),suffix,identify) + end + traverse("tree",withtree) -- TEXTREE only + if texconfig.kpse_init then + traverse("lsr", withlsr) else - traverse("system", function(suffix) -- OSFONTDIR cum suis - walk_tree(names.getpaths(trace),suffix,identify) - end) + traverse("system", withsystem) end - data.statistics.readfiles, data.statistics.skippedfiles, data.statistics.duplicatefiles = totalnofread, totalnofskipped, totalnofduplicates + data.statistics.readfiles = totalnofread + data.statistics.skippedfiles = totalnofskipped + data.statistics.duplicatefiles = totalnofduplicates end local function addfilenames() - local data = names.data + local data = names.data local specifications = data.specifications - local files = { } + local indices = { } + local files = { } for i=1,#specifications do local fullname = specifications[i].filename files[cleanfilename(fullname)] = fullname + indices[fullname] = i end - data.files = files + data.files = files + data.indices = indices end local function rejectclashes() -- just to be sure, so no explicit afm will be found then - local specifications, used, okay, o = names.data.specifications, { }, { }, 0 + local specifications = names.data.specifications + local used = { } + local okay = { } + local rejected = { } -- only keep modification + local o = 0 for i=1,#specifications do local s = specifications[i] local f = s.fontname if f then - local fnd, fnm = used[f], s.filename + local fnd = used[f] + local fnm = s.filename if fnd then if trace_warnings then - report_names( "fontname '%s' clashes, rejecting '%s' in favor of '%s'",f,fnm,fnd) + report_names("fontname %a clashes, %a rejected in favor of %a",f,fnm,fnd) end + rejected[f] = s.modification else used[f] = fnm o = o + 1 @@ -795,30 +913,37 @@ local function rejectclashes() -- just to be sure, so no explicit afm will be fo end local d = #specifications - #okay if d > 0 then - report_names( "%s files rejected due to clashes",d) + report_names("%s files rejected due to clashes",d) end names.data.specifications = okay + names.data.rejected = rejected end local function resetdata() - local mappings, fallbacks = { }, { } + local mappings = { } + local fallbacks = { } for _, k in next, filters.list do - mappings[k], fallbacks[k] = { }, { } + mappings [k] = { } + fallbacks[k] = { } end names.data = { - version = names.version, - mappings = mappings, - fallbacks = fallbacks, + version = names.version, + mappings = mappings, + fallbacks = fallbacks, specifications = { }, - families = { }, - statistics = { }, - datastate = resolvers.datastate(), + families = { }, + statistics = { }, + names = { }, + indices = { }, + rejected = { }, + datastate = resolvers.datastate(), } end -function names.identify() +function names.identify(force) + local starttime = os.gettimeofday() -- use elapser resetdata() - analyzefiles() + analyzefiles(not force and names.readdata(names.basename)) rejectclashes() collectfamilies() collectstatistics() @@ -827,6 +952,7 @@ function names.identify() checkduplicates() addfilenames() -- sorthashes() -- will be resorted when saved + report_names("total scan time %0.3f seconds",os.gettimeofday()-starttime) end function names.is_permitted(name) @@ -839,11 +965,11 @@ function names.readdata(name) return containers.read(names.cache,name) end -function names.load(reload,verbose) +function names.load(reload,force) if not names.loaded then if reload then if names.is_permitted(names.basename) then - names.identify(verbose) + names.identify(force) names.writedata(names.basename,names.data) else report_names("unable to access database cache") @@ -890,9 +1016,11 @@ function names.list(pattern,reload,all) -- here? local t = { } local data = names.data if data then - local list = filters.list - local mappings, sorted_mappings = data.mappings, data.sorted_mappings - local fallbacks, sorted_fallbacks = data.fallbacks, data.sorted_fallbacks + local list = filters.list + local mappings = data.mappings + local sorted_mappings = data.sorted_mappings + local fallbacks = data.fallbacks + local sorted_fallbacks = data.sorted_fallbacks for i=1,#list do local format = list[i] list_them(mappings[format],sorted_mappings[format],pattern,t,all) @@ -954,10 +1082,12 @@ end -- we could cache a lookup .. maybe some day ... (only when auto loaded!) local function foundname(name,sub) -- sub is not used currently - local data = names.data - local mappings, sorted_mappings = data.mappings, data.sorted_mappings - local fallbacks, sorted_fallbacks = data.fallbacks, data.sorted_fallbacks - local list = filters.list + local data = names.data + local mappings = data.mappings + local sorted_mappings = data.sorted_mappings + local fallbacks = data.fallbacks + local sorted_fallbacks = data.sorted_fallbacks + local list = filters.list -- dilemma: we lookup in the order otf ttf ttc ... afm but now an otf fallback -- can come after an afm match ... well, one should provide nice names anyway -- and having two lists is not an option @@ -966,7 +1096,7 @@ local function foundname(name,sub) -- sub is not used currently local found = mappings[l][name] if found then if trace_names then - report_names("resolved via direct name match: '%s'",name) + report_names("resolved via direct name match: %a",name) end return found end @@ -976,7 +1106,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 - report_names("resolved via fuzzy name match: '%s' => '%s'",name,fname) + report_names("resolved via fuzzy name match: %a onto %a",name,fname) end return found end @@ -986,7 +1116,7 @@ local function foundname(name,sub) -- sub is not used currently local found = fallbacks[l][name] if found then if trace_names then - report_names("resolved via direct fallback match: '%s'",name) + report_names("resolved via direct fallback match: %a",name) end return found end @@ -996,13 +1126,13 @@ 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 - report_names("resolved via fuzzy fallback match: '%s' => '%s'",name,fname) + report_names("resolved via fuzzy fallback match: %a onto %a",name,fname) end return found end end if trace_names then - report_names("font with name '%s' cannot be found",name) + report_names("font with name %a cannot be found",name) end end @@ -1248,40 +1378,39 @@ end local function collect(stage,found,done,name,weight,style,width,variant,all) local data = names.data - local families, sorted = data.families, data.sorted_families - strictname = "^".. name -- to be checked + local families = data.families + local sorted = data.sorted_families + local strictname = "^".. name -- to be checked local family = families[name] if trace_names then - report_names("resolving name '%s', weight '%s', style '%s', width '%s', variant '%s'", - name or "?",tostring(weight),tostring(style),tostring(width),tostring(variant)) + report_names("resolving name %a, weight %a, style %a, width %a, variant %a",name,weight,style,width,variant) end - --~ print(name,serialize(family)) if weight and weight ~= "" then if style and style ~= "" then if width and width ~= "" then if variant and variant ~= "" then if trace_names then - report_names("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 %a, weight %a, style %a, width %a, variant %a",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 - report_names("resolving stage %s, name '%s', weight '%s', style '%s', width '%s'",stage,name,weight,style,width) + report_names("resolving stage %s, name %a, weight %a, style %a, width %a",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 - report_names("resolving stage %s, name '%s', weight '%s', style '%s'",stage,name,weight,style) + report_names("resolving stage %s, name %a, weight %a, style %a",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 - report_names("resolving stage %s, name '%s', weight '%s'",stage,name,weight) + report_names("resolving stage %s, name %a, weight %a",stage,name,weight) end s_collect_weight(found,done,all,weight,family) m_collect_weight(found,done,all,weight,families,sorted,strictname) @@ -1289,26 +1418,26 @@ 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 - report_names("resolving stage %s, name '%s', style '%s', width '%s'",stage,name,style,width) + report_names("resolving stage %s, name %a, style %a, width %a",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 - report_names("resolving stage %s, name '%s', style '%s'",stage,name,style) + report_names("resolving stage %s, name %a, style %a",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 - report_names("resolving stage %s, name '%s', width '%s'",stage,name,width) + report_names("resolving stage %s, name %a, width %a",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 - report_names("resolving stage %s, name '%s'",stage,name) + report_names("resolving stage %s, name %a",stage,name) end s_collect(found,done,all,family) m_collect(found,done,all,families,sorted,strictname) @@ -1344,11 +1473,11 @@ local function heuristic(name,weight,style,width,variant,all) -- todo: fallbacks if nf then local t = { } for i=1,nf do - t[i] = format("'%s'",found[i].fontname) + t[i] = formatters["%a"](found[i].fontname) end - report_names("name '%s' resolved to %s instances: %s",name,nf,concat(t," ")) + report_names("name %a resolved to %s instances: % t",name,nf,t) else - report_names("name '%s' unresolved",name) + report_names("name %a unresolved",name) end end if all then @@ -1402,7 +1531,6 @@ function names.collectfiles(askedname,reload) -- no all 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] @@ -1414,77 +1542,25 @@ function names.collectfiles(askedname,reload) -- no all end end ---~ --[[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", ---~ } +-- 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.findfile(name,v) or "") ~= "" + found = (findfile(name,v) or "") ~= "" if found then return found end end - return ((resolvers.findfile(name,"tfm") or "") ~= "") or ((names.resolve(name) or "") ~= "") + return (findfile(name,"tfm") or "") ~= "" or (names.resolve(name) or "") ~= "" end --- for i=1,fonts.names.lookup(pattern) do --- texio.write_nl(fonts.names.getkey("filename",i)) --- end - local lastlookups, lastpattern = { }, "" function names.lookup(pattern,name,reload) -- todo: find @@ -1499,7 +1575,7 @@ function names.lookup(pattern,name,reload) -- todo: find lookups = families[pattern] end if trace_names then - report_names("starting with %s lookups for '%s'",#lookups,pattern) + report_names("starting with %s lookups for %a",#lookups,pattern) end if lookups then for key, value in gmatch(pattern,"([^=,]+)=([^=,]+)") do @@ -1523,7 +1599,7 @@ function names.lookup(pattern,name,reload) -- todo: find end end if trace_names then - report_names("%s matches for key '%s' with value '%s'",#t,key,value) + report_names("%s matches for key %a with value %a",#t,key,value) end lookups = t end @@ -1617,19 +1693,19 @@ 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) + report_names("resolving specification: %a to 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) + report_names("resolved by registered names: %a to %s",askedname,found.filename) end 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) + report_names("resolved by font database: %a to %s",askedname,found.filename) end return found.filename, found.subfont and found.rawname end |