summaryrefslogtreecommitdiff
path: root/tex/context/base/font-syn.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/font-syn.lua')
-rw-r--r--tex/context/base/font-syn.lua423
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)