diff options
Diffstat (limited to 'tex/context/base/font-syn.lua')
-rw-r--r-- | tex/context/base/font-syn.lua | 423 |
1 files changed, 90 insertions, 333 deletions
diff --git a/tex/context/base/font-syn.lua b/tex/context/base/font-syn.lua index 18da4f2e1..27176dade 100644 --- a/tex/context/base/font-syn.lua +++ b/tex/context/base/font-syn.lua @@ -12,14 +12,13 @@ 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, sortedhash = table.serialize, table.sortedhash +local serialize = table.serialize local lpegmatch = lpeg.match local unpack = unpack or table.unpack -local formatters, topattern = string.formatters, string.topattern +local formatters = string.formatters local allocate = utilities.storage.allocate local sparse = utilities.storage.sparse -local setmetatableindex = table.setmetatableindex local removesuffix = file.removesuffix local splitbase = file.splitbase @@ -35,13 +34,11 @@ local findfile = resolvers.findfile local cleanpath = resolvers.cleanpath local resolveresolved = resolvers.resolve -local settings_to_hash = utilities.parsers.settings_to_hash_tolerant - 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") +local report_names = logs.reporter("fonts","names") --[[ldx-- <p>This module implements a name to filename resolver. Names are resolved @@ -56,12 +53,9 @@ fonts.names = names local filters = names.filters or { } names.filters = filters -local treatments = names.treatments or { } -names.treatments = treatments - names.data = names.data or allocate { } -names.version = 1.123 +names.version = 1.110 names.basename = "names" names.saved = false names.loaded = false @@ -96,8 +90,7 @@ local weights = Cs ( -- not extra + P("heavy") + P("ultra") + P("black") ---+ P("bol") / "bold" -- blocks - + P("bol") + + P("bol") -- / "bold" + P("regular") / "normal" ) @@ -112,8 +105,8 @@ local styles = Cs ( + P("oblique") / "italic" + P("slanted") + P("roman") / "normal" - + P("ital") / "italic" -- might be tricky - + P("ita") / "italic" -- might be tricky + + P("ital") / "italic" + + P("ita") / "italic" ) local normalized_styles = sparse { @@ -185,28 +178,6 @@ names.knownvariants = { "smallcaps", } -local remappedweights = { - [""] = "normal", - ["bol"] = "bold", -} - -local remappedstyles = { - [""] = "normal", -} - -local remappedwidths = { - [""] = "normal", -} - -local remappedvariants = { - [""] = "normal", -} - -names.remappedweights = remappedweights setmetatableindex(remappedweights ,"self") -names.remappedstyles = remappedstyles setmetatableindex(remappedstyles ,"self") -names.remappedwidths = remappedwidths setmetatableindex(remappedwidths ,"self") -names.remappedvariants = remappedvariants setmetatableindex(remappedvariants,"self") - local any = P(1) local analyzed_table @@ -274,7 +245,6 @@ function fontloader.fullinfo(...) -- check with taco what we get / could get end filters.otf = fontloader.fullinfo -filters.ttf = fontloader.fullinfo function filters.afm(name) -- we could parse the afm file as well, and then report an error but @@ -287,7 +257,7 @@ function filters.afm(name) local f = io.open(name) if f then local hash = { } - for line in f:lines() do -- slow + for line in f:lines() do local key, value = match(line,"^(.+)%s+(.+)%s*$") if key and #key > 0 then hash[lower(key)] = value @@ -450,17 +420,15 @@ local function check_name(data,result,filename,modification,suffix,subfont) -- 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 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 italicangle = tonumber(result.italicangle) - local subfont = subfont or nil - local rawname = fullname or fontname or familyname - local filebase = removesuffix(basename(filename)) - local cleanfilename = cleanname(filebase) -- for WS + 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 italicangle = tonumber(result.italicangle) + local subfont = subfont or nil + local rawname = fullname or fontname or familyname -- normalize familyname = familyname and cleanname(familyname) fullname = fullname and cleanname(fullname) @@ -490,42 +458,27 @@ local function check_name(data,result,filename,modification,suffix,subfont) if not familyname then familyname = a_name end - fontname = fontname or fullname or familyname or filebase -- maybe cleanfilename + fontname = fontname or fullname or familyname or basename(filename) fullname = fullname or fontname familyname = familyname or fontname - -- we do these sparse - local units = result.units_per_em or 1000 - local minsize = result.design_range_bottom or 0 - local maxsize = result.design_range_top or 0 - local designsize = result.design_size or 0 - local angle = result.italicangle or 0 - local pfminfo = result.pfminfo - local pfmwidth = pfminfo and pfminfo.width or 0 - local pfmweight = pfminfo and pfminfo.weight or 0 - -- specifications[#specifications + 1] = { - filename = filename, -- unresolved - cleanfilename = cleanfilename, - 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, - units = units ~= 1000 and unit or nil, - pfmwidth = pfmwidth ~= 0 and pfmwidth or nil, - pfmweight = pfmweight ~= 0 and pfmweight or nil, - angle = angle ~= 0 and angle or nil, - minsize = minsize ~= 0 and minsize or nil, - maxsize = maxsize ~= 0 and maxsize or nil, - designsize = designsize ~= 0 and designsize or nil, - modification = modification ~= 0 and modification or nil, + 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 @@ -549,10 +502,10 @@ local function cleanupkeywords() 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" local variant = b_variant or c_variant or d_variant or e_variant or f_variant or "normal" - weight = remappedweights [weight or ""] - style = remappedstyles [style or ""] - width = remappedwidths [width or ""] - variant = remappedvariants[variant or ""] + if not weight or weight == "" then weight = "normal" end + if not style or style == "" then style = "normal" end + if not width or width == "" then width = "normal" end + if not variant or variant == "" then variant = "normal" end weights [weight ] = (weights [weight ] or 0) + 1 styles [style ] = (styles [style ] or 0) + 1 widths [width ] = (widths [width ] or 0) + 1 @@ -571,22 +524,12 @@ local function collectstatistics() local data = names.data local specifications = data.specifications if specifications then - local f_w = formatters["%i"] - local f_a = formatters["%0.2f"] - -- normal stuff - local weights = { } - local styles = { } - local widths = { } - local variants = { } - -- weird stuff - local angles = { } - -- extra stuff - local pfmweights = { } setmetatableindex(pfmweights,"table") - local pfmwidths = { } setmetatableindex(pfmwidths, "table") - -- main loop + local weights = { } + local styles = { } + local widths = { } + local variants = { } for i=1,#specifications do - local s = specifications[i] - -- normal stuff + local s = specifications[i] local weight = s.weight local style = s.style local width = s.width @@ -595,64 +538,13 @@ local function collectstatistics() 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 - -- weird stuff - local angle = f_a(tonumber(s.angle) or 0) - angles[angle] = (angles[angles] or 0) + 1 - -- extra stuff - local pfmweight = f_w(s.pfmweight or 0) - local pfmwidth = f_w(s.pfmwidth or 0) - local tweights = pfmweights[pfmweight] - local twidths = pfmwidths [pfmwidth] - tweights[pfmweight] = (tweights[pfmweight] or 0) + 1 - twidths[pfmwidth] = (twidths [pfmwidth] or 0) + 1 - end - -- - local stats = data.statistics - stats.weights = weights - stats.styles = styles - stats.widths = widths - stats.variants = variants - stats.angles = angles - stats.pfmweights = pfmweights - stats.pfmwidths = pfmwidths - stats.fonts = #specifications - -- - setmetatableindex(pfmweights,nil) - setmetatableindex(pfmwidths, nil) - -- - report_names("") - report_names("weights") - report_names("") - report_names(formatters[" %T"](weights)) - report_names("") - report_names("styles") - report_names("") - report_names(formatters[" %T"](styles)) - report_names("") - report_names("widths") - report_names("") - report_names(formatters[" %T"](widths)) - report_names("") - report_names("variants") - report_names("") - report_names(formatters[" %T"](variants)) - report_names("") - report_names("angles") - report_names("") - report_names(formatters[" %T"](angles)) - report_names("") - report_names("pfmweights") - report_names("") - for k, v in sortedhash(pfmweights) do - report_names(formatters[" %-10s: %T"](k,v)) - end - report_names("") - report_names("pfmwidths") - report_names("") - for k, v in sortedhash(pfmwidths) do - report_names(formatters[" %-10s: %T"](k,v)) end - report_names("") + local stats = data.statistics + stats.weights = weights + stats.styles = styles + stats.widths = widths + stats.variants = variants + stats.fonts = #specifications end end @@ -716,11 +608,8 @@ local function checkduplicate(where) -- fails on "Romantik" but that's a border local specifications = data.specifications local loaded = { } if specifications and mapping then - -- was: for _, m in sortedhash(mapping) do - local order = filters.list - for i=1,#order do - local m = mapping[order[i]] - for k, v in sortedhash(m) do + for _, m in next, mapping do + for k, v in next, m do local s = specifications[v] 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] @@ -744,7 +633,7 @@ local function checkduplicate(where) -- fails on "Romantik" but that's a border end end local n = 0 - for k, v in sortedhash(loaded) do + for k, v in table.sortedhash(loaded) do local nv = #v if nv > 1 then if trace_warnings then @@ -831,7 +720,7 @@ local function analyzefiles(olddata) local oldindices = olddata and olddata.indices or { } local oldspecifications = olddata and olddata.specifications or { } local oldrejected = olddata and olddata.rejected or { } - local treatmentdata = treatments.data or { } -- when used outside context + local treatmentdata = fonts.treatments.data local function identify(completename,name,suffix,storedname) local pathpart, basepart = splitbase(completename) nofread = nofread + 1 @@ -1065,13 +954,12 @@ function names.identify(force) analyzefiles(not force and names.readdata(names.basename)) rejectclashes() collectfamilies() - -- collectstatistics() + collectstatistics() cleanupkeywords() collecthashes() checkduplicates() addfilenames() -- sorthashes() -- will be resorted when saved - collectstatistics() report_names("total scan time %0.3f seconds",os.gettimeofday()-starttime) end @@ -1683,131 +1571,46 @@ end local lastlookups, lastpattern = { }, "" --- function names.lookup(pattern,name,reload) -- todo: find --- if lastpattern ~= pattern then --- names.load(reload) --- local specifications = names.data.specifications --- local families = names.data.families --- local lookups = specifications --- if name then --- lookups = families[name] --- elseif not find(pattern,"=") then --- lookups = families[pattern] --- end --- if trace_names then --- report_names("starting with %s lookups for %a",#lookups,pattern) --- end --- if lookups then --- for key, value in gmatch(pattern,"([^=,]+)=([^=,]+)") do --- local t, n = { }, 0 --- if find(value,"*") then --- value = 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 --- report_names("%s matches for key %a with value %a",#t,key,value) --- end --- lookups = t --- end --- end --- lastpattern = pattern --- lastlookups = lookups or { } --- end --- return #lastlookups --- end - -local function look_them_up(lookups,specification) - for key, value in next, specification do - local t, n = { }, 0 - if find(value,"*") then - value = 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 - report_names("%s matches for key %a with value %a",#t,key,value) - end - lookups = t - end - return lookups -end - -local function first_look(name,reload) - names.load(reload) - local data = names.data - local specifications = data.specifications - local families = data.families - if name then - return families[name] - else - return specifications - end -end - function names.lookup(pattern,name,reload) -- todo: find - names.load(reload) - local data = names.data - local specifications = data.specifications - local families = data.families - local lookups = specifications - if name then - name = cleanname(name) - end - if type(pattern) == "table" then - local familyname = pattern.familyname - if familyname then - familyname = cleanname(familyname) - pattern.familyname = familyname + if lastpattern ~= pattern then + names.load(reload) + local specifications = names.data.specifications + local families = names.data.families + local lookups = specifications + if name then + lookups = families[name] + elseif not find(pattern,"=") then + lookups = families[pattern] end - local lookups = first_look(name or familyname,reload) - if lookups then - if trace_names then - report_names("starting with %s lookups for '%T'",#lookups,pattern) - end - lookups = look_them_up(lookups,pattern) + if trace_names then + report_names("starting with %s lookups for %a",#lookups,pattern) end - lastpattern = false - lastlookups = lookups or { } - elseif lastpattern ~= pattern then - local lookups = first_look(name or (not find(pattern,"=") and pattern),reload) if lookups then - if trace_names then - report_names("starting with %s lookups for %a",#lookups,pattern) - end - local specification = settings_to_hash(pattern) - local familyname = specification.familyname - if familyname then - familyname = cleanname(familyname) - specification.familyname = familyname + for key, value in gmatch(pattern,"([^=,]+)=([^=,]+)") do + 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 + report_names("%s matches for key %a with value %a",#t,key,value) + end + lookups = t end - lookups = look_them_up(lookups,specification) end lastpattern = pattern lastlookups = lookups or { } @@ -1919,49 +1722,3 @@ function names.resolvespec(askedname,sub) -- overloads previous definition report_names("unresolved: %s",askedname) end end - --- We could generate typescripts with designsize info from the name database but --- it's not worth the trouble as font names remain a mess: for instance how do we --- idenfity a font? Names, families, subfamilies or whatever snippet can contain --- a number related to the design size and so we end up with fuzzy logic again. So, --- instead it's easier to make a few goody files. --- --- local hash = { } --- --- for i=1,#specifications do --- local s = specifications[i] --- local min = s.minsize or 0 --- local max = s.maxsize or 0 --- if min ~= 0 or max ~= 0 then --- -- the usual name mess: --- -- antykwa has modifiers so we need to take these into account, otherwise we get weird combinations --- -- ebgaramond has modifiers with the size encoded, so we need to strip this in order to recognized similar styles --- -- lm has 'slanted appended in some names so how to choose that one --- -- --- local modifier = string.gsub(s.modifiers or "normal","%d","") --- -- print funny modifier --- local instance = string.formatters["%s-%s-%s-%s-%s-%s"](s.familyname,s.width,s.style,s.weight,s.variant,modifier) --- local h = hash[instance] --- if not h then --- h = { } --- hash[instance] = h --- end --- size = string.formatters["%0.1fpt"]((min)/10) --- h[size] = s.filename --- end --- end --- --- local newhash = { } --- --- for k, v in next, hash do --- if next(v,next(v)) then --- -- local instance = string.match(k,"(.+)%-.+%-.+%-.+$") --- local instance = string.match(k,"(.+)%-.+%-.+$") --- local instance = string.gsub(instance,"%-normal$","") --- if not newhash[instance] then --- newhash[instance] = v --- end --- end --- end --- --- inspect(newhash) |