diff options
author | Taco Hoekwater <taco@elvenkind.com> | 2011-06-01 08:54:21 +0000 |
---|---|---|
committer | Taco Hoekwater <taco@elvenkind.com> | 2011-06-01 08:54:21 +0000 |
commit | d7ccb42582f85acf30568913610ccf4d602023fb (patch) | |
tree | 7292e3545a420676878e7451b68892d360c62cb6 /Master/texmf-dist/tex/context/base/font-syn.lua | |
parent | 2d62a6fe9b80def59c392268022f1f9a2d6e358f (diff) |
commit context 2011.05.18
git-svn-id: svn://tug.org/texlive/trunk@22719 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/context/base/font-syn.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/font-syn.lua | 597 |
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 |